package com.gradle.quartz.batch.config;

import com.gradle.bean.user.User;
import com.gradle.quartz.batch.service.UserService;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.adapter.ItemProcessorAdapter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.batch.item.support.CompositeItemProcessor;
import org.springframework.batch.item.validator.BeanValidatingItemProcessor;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;

import java.io.*;
import java.util.Arrays;

/**
 * 逻辑现有两条
 * 第一条普通任务 job ---> step ---> tasklet
 * 第二条：要读取文件
 * job ---> step ---> chunk ---> reader ----> writer
 *
 * @author ldanniel
 */
@EnableBatchProcessing
@Configuration
public class CompositeConfig {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    private UserService userService;
    @Autowired
    private UseFieldMapper useFieldMapper;
    @Bean
    public ItemWriter<User> compositeWriter() throws FileNotFoundException {
        return new FlatFileItemWriterBuilder<User>()
                .name("userFlatItemWriter")
                .resource(new PathResource("D:\\workspace\\mygradleproject\\readerOut\\readerOut.txt"))
                //指定输出格式
                .formatted()
                .format("id:%s,姓名：%s,年龄：%s,联系地址:%s")
                .names("id", "userName", "age", "address")
                .build();
    }


    @Bean
    public ItemProcessorAdapter<User, User> compositeAdapter() {
        ItemProcessorAdapter<User, User> adapter = new ItemProcessorAdapter<>();
        //适配器反射读取的方法
        adapter.setTargetMethod("queryUserInfo");
        //适配器反射读取的类
        adapter.setTargetObject(userService);
        return adapter;
    }

    @Bean
    public BeanValidatingItemProcessor<User> compositeBeanValidatingItemProcessor() {
        System.out.println("---------------执行参数校验------------------");
        BeanValidatingItemProcessor<User> processor = new BeanValidatingItemProcessor<>();
        //不满足条件丢弃
        processor.setFilter(true);
        return processor;
    }

    /**
     * 读取平面文件
     *
     * @return FlatFileItemReader<User>
     */
    @Bean
    public FlatFileItemReader<User> compositeReader() {
        return new FlatFileItemReaderBuilder<User>()
                .name("userItemReader")
                .resource(new ClassPathResource("/file/user.txt"))
                //指定解析器，使用#分割，默认是用,号
                .delimited().delimiter("#")
                //截取数据之后，数据怎么命名
                .names("id", "userName", "age", "province", "city", "area")
                //将解析的数据封装到User对象中
//                .targetType(User.class) 自动封装
                .fieldSetMapper(useFieldMapper)
                .build();
    }


    @Bean
    public CompositeItemProcessor<User, User> compositeItemProcessor() {
        System.out.println("--------------开始执行组合校验器--------------");
        CompositeItemProcessor<User, User> compositeProcessor = new CompositeItemProcessor<>();
        //各种校验器组合
        compositeProcessor.setDelegates(Arrays.asList(compositeBeanValidatingItemProcessor(), compositeAdapter()));
        return compositeProcessor;
    }

    /**
     * 处理任务的逻辑对象
     *
     * @return Tasklet
     */
    @Bean
    public Tasklet compositeTaskLet() {
        return (contribution, chunkContext) -> {
            System.out.println(">>>>>>>>>处理任务的逻辑对象【Tasklet】>>>>>>>>");
            return RepeatStatus.FINISHED;
        };
    }

    @Bean
    public Step compositeStep() throws FileNotFoundException {
        System.out.println(">>>>>>>>>tasklet要执行step的逻辑 类似Thread的runnable【Step】>>>>>>>>");
        return stepBuilderFactory.get("compositeStep")
                //一次性读多少数据,以及数据类型为User
                .<User, User>chunk(1)
                .reader(compositeReader())
                //组合处理器
                .processor(compositeItemProcessor())
                .writer(compositeWriter())
                .build();
    }

    @Bean
    public Job job() throws Exception {
        System.out.println(">>>>>>>>>任务启动执行对象【Job】>>>>>>>>");
        return jobBuilderFactory.get("writer-processor-job")
                .start(compositeStep())
                .incrementer(new RunIdIncrementer())
                .build();
    }
}
